#file: makefile
#autor: jiang xinpeng
#time:2021.1.1
#update：2021.10.14
#copyright: (C) 2020-2050 by jiang xinpeng,All right are reserved.

#arch
ARCH = X86	#switch compiler architure
export ARCH 

#system environment  
ifeq ($(OS),Windows_NT)
	SCRIPTDIR= ./script/windows
	WORKDIR = ./CATOS
else
	SCRIPTDIR = ./script/linux
	WORKDIR = ./CATOS
endif

#tools
MAKE=make
DD = dd 
MKDIR = mkdir 
OBJDUMP = objdump 
RM = rm
TRUNC = truncate
CC=gcc 
LD=ld
GDB=gdb
HOSTCC = gcc 
NASM = nasm 
ECHO = echo
MKFS = mkfs.msdos
MCOPY = mtools -c mcopy 
IMC_CREATE = qemu-img create
VDISK_MAP = qemu-nbd
ENABLE_VDISK = modprobe nbd max_part=8
FDISK = fdisk

#machine 
QEMU = qemu-system-i386
BOCHS= bochs

#dir
KERNELDIR = ./src
ARCHDIR = $(KERNELDIR)/arch/$(ARCH)
USERAPP_DIR = ./userapp
SYSAPP_DIR =./sysapp
BIN_DIR = ./bin 
SBIN_DIR =./sbin
LIBS_DIR = ./libs
TOOLS_DIR = ./tools
GRUB_DIR = $(TOOLS_DIR)/grub 
BIOS_FW_DIR = $(TOOLS_DIR)/bios_fw
IMAGE_DIR = ./develop/img
ROM_DIR = ./develop/rom

#image 
DISK1_IMG = $(IMAGE_DIR)/CatOS.vhd
DISK2_IMG = $(IMAGE_DIR)/CatOS.vhd

#image size
DISK1_SIZE = 536870912  #512MB
DISK2_SIZE = 536870912 #512MB

#boot disk image
BOOT_DISK = $(DISK1_IMG)

#data disk image
FS_DISK = $(DISK2_IMG)

#bin file sectors offset
BOOT_SEEK = 1
BOOT_COUNT = 1

LOADER_SEEK = 2
LOADER_COUNT =8

SETUP_SEEK = 10 
SETUP_COUNT = 90

KERNEL_SEEK = 1000
KERNEL_COUNT = 1024 

#kernel name 
OS_NAME = CATOS

#kernel file
KERNEL_ELF = $(OS_NAME).elf 
export KERNEL_ELF

#elf mode
ELF_BOOT_MODE ?= n 

#net module 
KERNEL_MODULE_NET ?= n
export KERNEL_MODULE_NET

#livecd mode
KERNEL_LIVECD_MODE ?= n 
export KERNEL_LIVECD_MODE

#vbe mode
KERNEL_VBE_MODE ?= y
export KERNEL_VBE_MODE

#qemu sound 
QEMU_SOUND ?= y

#AHCI disk
DISK_AHCI = y

#SMP enable
SMP_ENABLE = n
export SMP_ENABLE

#boot mode
export BOOT_GRUB2_MODE = GRUB2 
export BOOT_LEGACY_MODE = LEGACY

#boot bin
BOOT_BIN = $(ARCHDIR)/boot/legacy/mbr.bin
LOADER_BIN = $(ARCHDIR)/boot/legacy/loader.bin
SETUP_BIN = $(ARCHDIR)/boot/legacy/setup.bin

#set boot mode default
BOOT_MODE ?= $(BOOT_GRUB2_MODE)

#dump 
DUMP_FILE ?= $(KERNELDIR)/$(KERNEL_ELF)
DUMP_FLAGS ?= 

#bochs config
BOCHS_SCRIPT = ./script/bochs
BOCHSRC_WIN = $(BOCHS_SCRIPT)/bochsrc.win #bochsrc for windows
BOCHSRC_LINUX = $(BOCHS_SCRIPT)/bochsrc.linux #bochsrc for linux

#vbox
VBOX_NAME = "CatOS" #vbox name
VBOX_MEM = 536870912 #vbox mem size 512MB

# qemu config
#qemu kvm 
ifeq ($(OS),Windows_NT)
QEMU_KVM := -accel hax
else 
QEMU_KVM := -enable-kvm 
endif
QEMU_KVM := #no virtual

# qemu baisc config 
# boot from:
#		 a floppy b harddisk c iso
QEMU_ARGUMENT := -m 4G $(QEMU_KVM) \
				-name "CatOS" \
				-rtc base=localtime \
				-boot d \
				-serial stdio \
				-drive file="$(DISK1_IMG)",if=ide,media=disk,index=1,format=vpc

# qemu sound config 
ifeq ($(QEMU_SOUND),y)
QEMU_ARGUMENT += -device sb16 \
				-device AC97 \
				-device intel-hda -device hda-duplex 
endif

ifeq ($(SMP_ENABLE),y)
QEMU_ARGUMENT += -smp 2,sockets=1
endif

# qemu disk device config
ifeq ($(KERNEL_LIVECD_MODE),n)
	ifeq ($(DISK_AHCI),y)
	QEMU_ARGUMENT += -drive id=disk1,file=$(DISK2_IMG),format=raw,if=none \
					   -device ahci,id=ahci \
					   -device ide_hd,driver=disk1,bus=ahci.1 
	else 
	QEMU_ARGUMENT +=  -drive file="/CatOS.vhd",if=ide,media=disk,index=1,format=vpc
	endif
endif

# qemu boot 
ifeq ($(BOOT_MODE),$(BOOT_LEGACY_MODE))
QEMU_ARGUMENT += -drive id=disk0,file=$(DISK1_IMG),format=raw,if=none 
			-device ide_hd,driver=disk0,bus=ahci.0
endif

# qemu net config
ifeq ($(KERNEL_MODULE_NET),y)
QEMU_ARGUMENT += -net nic,model=rtl8139 -net tap,ifname=tap0,script=no,downscript=no
endif

#cmd
.PHONY : all kernel build  debuild qemu qemudbg app app_clean dump 

#default operator
#make image 
all : kernel
	@$(ECHO) [image] start create image file
ifeq ($(BOOT_MODE),$(BOOT_LEGACY_MODE))		#legacy boot
	$(DD) if=$(BOOT_BIN) of=$(BOOT_DISK) bs=512 count=1 conv=notrunc 
	$(DD) if=$(LOADER_BIN) of=$(BOOT_DISK) bs=512 seek=$(LOADER_SEEK) count=$(LOADER_COUNT) conv=notrunc
	$(DD) if=$(SETUP_BIN) of=$(BOOT_DISK) bs=512 seek=$(SETUP_SEEK) count=$(SETUP_COUNT) conv=notrunc 
	$(DD) if=$(KERNEL_ELF) of=$(BOOT_DISK) bs=512 seek=$(KERNEL_SEEK) count=$(KERNEL_COUNT) conv=notrunc 
else 
ifeq ($(BOOT_MODE),$(BOOT_GRUB2_MODE))	 #grub boot
	$(MAKE) -s -C $(GRUB_DIR) KERNEL=$(subst $(KERNELDIR)/,,$(KERNEL_ELF)) OS_NAME=$(OS_NAME)
endif 
endif 

#run(support: qemu bochs)
run : qemu 

#start qemu
qemu : all
	@$(ECHO) [qemu] ready to start qemu virtual machine
ifeq ($(BOOT_MODE),$(BOOT_LEGACY_MODE))
	$(QEMU) $(QEMU_ARGUMENT)
else 
ifeq ($(BOOT_MODE),$(BOOT_GRUB2_MODE))
ifeq ($(ELF_BOOT_MODE),n) #legacy boot
	$(QEMU) $(QEMU_ARGUMENT) -cdrom $(KERNELDIR)/$(OS_NAME).iso 
else 					  #uefi boot
	$(QEMU) $(QEMU_ARGUMENT) -cdrom $(KERNELDIR)/$(OS_NAME).iso 
endif
endif
endif

QEMU_GDB_OPT := -S -gdb tcp::10001,ipv4 
#qemu start gdb server
qemudbg:
	@$(ECHO) [qemudbg] ready to start qemudbg 
ifeq ($(BOOT_MODE),$(BOOT_LEGACY_MODE))
	$(QEMU) $(QEMU_GDB_OPT) $(QEMU_ARGUMENT)
else 
ifeq ($(BOOT_MODE),$(BOOT_GRUB2_MODE))
ifeq ($(EFI_BOOT_MODE),n)	#legacy boot
	$(QEMU) $(QEMU_GDB_OPT) $(QEMU_ARGUMENT) -cdrom $(KERNELDIR)/$(OS_NAME).iso 
else 						#uefi boot
	$(QEMU) $(QEMU_GDB_OPT) $(QEMU_ARGUMENT) -cdrom $(KERNELDIR)/$(OS_NAME).iso
endif
endif
endif

bochs:
ifeq ($(OS),Windows_NT)
	$(BOCHS) -q -f $(BOCHSRC_WIN) 
else 
	$(BOCHS) -q -f $(BOCHSRC_LINUX)
endif

bochsdbg:
	@$(ECHO) [bochsdbg] ready to start bochsdbg 
ifeq ($(OS),Windows_NT)
	$(BOCHS) -q -f $(BOCHSRC_WIN)
else 
	$(BOCHS) -q -f $(BOCHSRC_LINUX)
endif

#start vbox
vbox:
	@$(ECHO) [vbox] ready to start vbox virtual machine
	$(VBOX) createvm $(VBOX_NAME) --register   
	$(VBOX) modifyvm $(VBOX_NAME) --ostype Other
	$(VBOX) modifyvm $(VBOX_NAME) --memory $(VBOX_MEM)
	$(VBOX) storagectl $(VBOX_NAME) --name IDE --add ide --controller PIIX4 -bootable on
	$(VBOX) storagectl $(VBOX_NAME) --name SATA --add sata --controller IntelAhci --bootable on 
	$(VBOX) storageattach $(VBOX_NAME) --name IDE --port 0 --device 0 --type dvddriver --medium $(DISK1_IMG) 
	$(VBOX) storageattach $(VBOX_NAME) --name IDE --port 1 --device 0 --type dvddriver --medium $(DISK2_IMG)
	$(VBOX) storageattach $(VBOX_NAME) --name SATA --port 0 --device 0 --type dvddriver --medium $(DISK1_IMG)
	$(VBOX) storageattach $(VBOX_NAME) --name SATA --port 1 --device 0 --type dvddriver --medium $(DISK2_IMG)
ifeq ($(KERNEL_MODULE_NET),y)
	$(VBOX) modifyvm $(VBOX_NAME) -nic1 bridged --nictype1 82545EM --cableconnected1 on --bridgedapter1 enp5s0f0 
endif
	$(VBOX) startvm $(VBOX_NAME) --type gui 

#compiler kernel 
kernel:
	@$(ECHO) [kernel] compiler kernel 
	$(MAKE) -s -C $(KERNELDIR) 

#del kernel 
clean: 
	@$(ECHO) [kernel] clean 
	$(MAKE) -s -C $(KERNELDIR) clean 

#build enviroment
build:
	@$(ECHO) start build compiler enviroment
	-$(MKDIR) $(IMAGE_DIR)
	-$(MKDIR) $(ROM_DIR)/userapp
	-$(MKDIR) $(ROM_DIR)/sysapp
	-$(MKDIR) $(ROM_DIR)/bin
	-$(MKDIR) $(ROM_DIR)/sbin

	$(MAKE) -s -C $(LIBS_DIR)

ifeq ($(KERNEL_VBE_MODE),y) #graph mode
	@$(ECHO) start compiler window appliction
	$(MAKE) -s -C $(SYSAPP_DIR)
	$(MAKE) -s -C $(USERAPP_DIR)
endif
	@$(ECHO) start compiler terminal appliction
	$(MAKE) -s -C $(BIN_DIR)
	$(MAKE) -s -C $(SBIN_DIR)

	-@$(SCRIPTDIR)/vhdmount.sh
	-@$(SCRIPTDIR)/copyfile.sh
	-@$(SCRIPTDIR)/vhdumount.sh

#del enviroment
debuild:
	@$(ECHO) start clean enviroment  
	$(MAKE) -s -C $(KERNELDIR) clean
	$(MAKE) -s -C $(SYSAPP_DIR) clean
	$(MAKE) -s -C $(USERAPP_DIR) clean 
	$(MAKE) -s -C $(BIN_DIR) clean
	$(MAKE) -s -C $(SBIN_DIR) clean
	$(MAKE) -s -C $(LIBS_DIR) clean
	$(MAKE) -s -C $(GRUB_DIR) clean
ifeq ($(KERNEL_VBE_MODE),y) #graph mode
	@-$(RM) -r $(ROM_DIR)/userapp
	@-$(RM) -r $(ROM_DIR)/sysapp
endif
	@-$(RM) -r $(ROM_DIR)/bin
	@-$(RM) -r $(ROM_DIR)/sbin
	@-$(RM) -r $(ROM_DIR)/account
	@-$(RM) -r ./src/$(OS_NAME).iso
	@-$(RM) -r $(DISK1_IMG)

#clean app
appclean:
	$(MAKE)

#compiler library
lib :	
	@$(ECHO) start compiler appliction library
	$(MAKE) -s -C $(LIBS_DIR) 

#compiler app 
app : 
	$(ECHO) start build app
	$(MAKE) -s -C $(LIBS_DIR) 
ifeq ($(KERNEL_VBE_MODE),y)
	$(MAKE) -s -C $(SYSAPP_DIR) 
	$(MAKE) -s -C $(USERAPP_DIR) 
endif
	$(MAKE) -s -C $(BIN_DIR) 
	$(MAKE) -s -C $(SBIN_DIR)
	
#del app 
app_clean :
	$(ECHO) start clean app 
	$(MAKE) -s -C $(LIBS_DIR) clean
ifeq ($(KERNEL_VBE_MODE),y)
	$(MAKE) -s -C $(SYSAPP_DIR) clean 
	$(MAKE) -s -C $(USERAPP_DIR) clean 
endif
	$(MAKE) -s -C $(BIN_DIR) clean 
	$(MAKE) -s -C $(SBIN_DIR) clean 
	
#dump kernel
dump :
	-$(RM) -rf $(OS_NAME).dump
	$(OBJDUMP) $(DUMP_FLAGS) -M intel -D $(DUMP_FILE) > $(OS_NAME).dump

#start gdb debug
gdb :
	$(GDB) $(KERNELDIR)/$(KERNEL_ELF)





 